//
//  JDPlayer.swift
//  funcode
//
//  Created by Wan Jiading on 2017/2/8.
//  Copyright © 2017年 WanJiading. All rights reserved.
//

import UIKit
import AVFoundation

enum JDPlayerState: Int {
	case buffering 	= 1
	case playing 	= 2
	case stoped		= 3
	case pause		= 4
}

let kJDPlayerStateChangedNotification    = "JDPlayerStateChangedNotification";
let kJDPlayerProgressChangedNotification = "JDPlayerProgressChangedNotification";
let kJDPlayerLoadProgressChangedNotification = "JDPlayerLoadProgressChangedNotification";

class JDPlayer: NSObject, JDResourceLoaderDelegate {
	
	let kScreenHeight		= UIScreen.main.bounds.height
	let kScreenWidth		= UIScreen.main.bounds.width
	
	var _state				: JDPlayerState = .stoped
	var state				: JDPlayerState {
		set {
			if newValue == .buffering {
				DebugLog("正在 缓冲")
			}
			
			if newValue == _state {
				return
			}
			
			_state = newValue
			NotificationCenter.default.post(name: NSNotification.Name(rawValue: kJDPlayerStateChangedNotification), object: nil)
		}
		get {
			return _state
		}
	}
	
	// 缓冲进度
	var _loadedProgress 	: Float = 0
	var loadedProgress		: Float {
		set {
			if _loadedProgress == newValue {
				return
			}
			
			_loadedProgress = newValue
			NotificationCenter.default.post(name: NSNotification.Name(rawValue: kJDPlayerLoadProgressChangedNotification), object: nil)
		}
		get {
			return _loadedProgress
		}
	}
	
	
	var duration			: CGFloat = 0.0 // 视频总时间
 	var current				: CGFloat = 0.0 // 当前播放时间
	var stopWhenAppDidEnterBackground = false
	
	var videoURLAsset		: AVURLAsset!
	var videoAsset			: AVAsset!
	var resouerLoader		: JDResourceLoader!
	var player				: AVPlayer?
	var currentPlayerItem	: AVPlayerItem?
	var currentPlayerLayer	: AVPlayerLayer!
	var playbackTimeObserver: NSObject!
	var isPauseByUser		: Bool = false // 是否被用户暂停
	var isLocalVideo		: Bool = false // 是否播放本地文件
	var isFinishLoad		: Bool = false // 是否下载完毕
	
	var showView			: UIView!
	
	var navBar				: UIView?
	var currentTimeLabel	: UILabel?
	var totalTimeLabel		: UILabel?
	var videoProgressView	: UIProgressView? // 缓冲进度条
	var playSlider			: UISlider? // 滑竿
	var stopButton			: UIButton? // 播放暂停按钮
	var screenButton		: UIButton? // 全屏按钮
	var isFullScreen		: Bool = false
	
	private static let instance: JDPlayer = JDPlayer()
	class var shared: JDPlayer {
		
		instance.isPauseByUser = true
		instance.state = JDPlayerState.stoped
		
		return instance
	}
	
	
	public func play(_ url: URL, _ showView: UIView) {
		self.player?.pause()
		self.releasePlayer()
		self.isPauseByUser = false
		self.loadedProgress = 0
		self.duration = 0
		self.current = 0
		self.showView = showView
		
		let path = JDPlayerUtil.tempVideoFilePath()
		try? SharedFileManager.removeItem(atPath: path!)
		
		// 本地文件
		if !url.absoluteString.hasPrefix("http") {
			
		} else {
		
			if self.resouerLoader == nil {
				self.resouerLoader = JDResourceLoader()
				self.resouerLoader.delegate = self
			}
			
			let playUrl = self.resouerLoader.getSchemeVideoURL(url)
			if playUrl == nil {
				DebugLog("【失败】playUrl == nil")
				return
			}
			
			self.videoURLAsset = AVURLAsset(url: playUrl!, options: nil)
			self.videoURLAsset.resourceLoader.setDelegate(self.resouerLoader, queue: DispatchQueue.main)
			self.currentPlayerItem = AVPlayerItem(asset: self.videoURLAsset)

			
			self.player?.pause()
			self.player?.replaceCurrentItem(with: nil)
			self.player?.pause()
			self.player = nil
		
			
			if self.player == nil {
				self.player = AVPlayer(playerItem: self.currentPlayerItem)
			} else {
				self.player!.replaceCurrentItem(with: self.currentPlayerItem)
			}
			self.currentPlayerLayer = AVPlayerLayer(player: self.player)
			self.currentPlayerLayer.frame = CGRect(x: CGFloat(0), y: CGFloat(44), width: CGFloat(showView.bounds.size.width), height: CGFloat(showView.bounds.size.height - 44))
			self.isLocalVideo = false
			
		}
		
		showView.layer.addSublayer(self.currentPlayerLayer)
		
		self.currentPlayerItem!.addObserver(self, forKeyPath: "status", options: .new, context: nil)
		self.currentPlayerItem!.addObserver(self, forKeyPath: "loadedTimeRanges", options: .new, context: nil)
		self.currentPlayerItem!.addObserver(self, forKeyPath: "playbackBufferEmpty", options: .new, context: nil)
		self.currentPlayerItem!.addObserver(self, forKeyPath: "playbackLikelyToKeepUp", options: .new, context: nil)
		
		NotificationCenter.default.addObserver(self, selector: #selector(self.appDidEnterBackground), name: NSNotification.Name.UIApplicationWillResignActive, object: nil)
		NotificationCenter.default.addObserver(self, selector: #selector(self.appDidEnterPlayGround), name: NSNotification.Name.UIApplicationDidBecomeActive, object: nil)
		NotificationCenter.default.addObserver(self, selector: #selector(self.playerItemDidPlayToEnd), name: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: self.currentPlayerItem)
		NotificationCenter.default.addObserver(self, selector: #selector(self.playerItemPlaybackStalled), name: NSNotification.Name.AVPlayerItemPlaybackStalled, object: self.currentPlayerItem)
		
		// 本地文件不设置JDPlayerStateBuffering状态
		if (url.scheme == "file") {
			// 如果已经在JDPlayerStatePlaying，则直接发通知，否则设置状态
			if self.state == JDPlayerState.playing {
				NotificationCenter.default.post(name: NSNotification.Name(rawValue: kJDPlayerStateChangedNotification), object: nil)
			}
			else {
				self.state = JDPlayerState.playing
			}
		}
		else {
			// 如果已经在JDPlayerStateBuffering，则直接发通知，否则设置状态
			if self.state == JDPlayerState.buffering {
				NotificationCenter.default.post(name: NSNotification.Name(rawValue: kJDPlayerStateChangedNotification), object: nil)
			}
			else {
				self.state = JDPlayerState.buffering
			}
		}

		if self.navBar == nil {
			self.navBar = UIView()
			showView.addSubview(self.navBar!)
		}
		self.buildVideoNavBar()
		
		// 显示HUD
//		XCHudHelper.sharedInstance().showHud(on: self.showView, caption: nil, image: nil, acitivity: true, autoHideTime: 0)
		
		NotificationCenter.default.post(name: NSNotification.Name(rawValue: kJDPlayerProgressChangedNotification), object: nil)
		let tap = UITapGestureRecognizer(target: self, action: #selector(self.halfScreen))
		showView.addGestureRecognizer(tap)
	
	}
	
	public func seek(_ seconds: CGFloat) {
		if self.state == JDPlayerState.stoped {
			return
		}
		
		var s = max(0, seconds)
		s = min(s, self.duration)
		self.player?.pause()
		
		self.player?.seek(to: CMTime.init(seconds: Double(s), preferredTimescale: 1)) { [unowned self] (finished) in
			self.isPauseByUser = false
			self.player?.play()
			if !self.currentPlayerItem!.isPlaybackLikelyToKeepUp {
				self.state = JDPlayerState.buffering
				
				// TODO HUD提醒
			}
		}
		
	}
	
	public func pause() {
		
		if self.currentPlayerItem == nil {
			return
		}
		self.stopButton!.setImage(UIImage(named: "icon_play"), for: .normal)
		self.stopButton!.setImage(UIImage(named: "icon_play_hl"), for: .highlighted)
		self.isPauseByUser = true
		self.state = JDPlayerState.pause
		self.player?.pause()
	}
	
	public func resume() {
		if self.currentPlayerItem == nil {
			return
		}
		self.stopButton!.setImage(UIImage(named: "icon_pause"), for: .normal)
		self.stopButton!.setImage(UIImage(named: "icon_pause_hl"), for: .highlighted)
		self.isPauseByUser = false
		self.player?.play()
	}
	
	public func stop() {
		
		self.isPauseByUser = true
		self.loadedProgress = 0
		self.duration = 0
		self.current = 0
		self.state = JDPlayerState.stoped
		self.player?.pause()
		self.releasePlayer()
		NotificationCenter.default.post(name: NSNotification.Name(rawValue: kJDPlayerProgressChangedNotification), object: nil)
	}
	
	/// 播放进度
	var progress: CGFloat {
		if self.duration > 0 {
			return self.current / self.duration
		}
		return 0
	}
	
	func fullScreen() {
		self.navBar!.isHidden = true
		self.currentPlayerLayer.transform = CATransform3DMakeRotation(.pi / 2, 0, 0, 1)
		self.currentPlayerLayer.frame = CGRect(x: CGFloat(0), y: CGFloat(0), width: CGFloat(kScreenWidth), height: CGFloat(kScreenHeight))
	}
	
	func halfScreen() {
		self.navBar!.isHidden = false
		self.currentPlayerLayer.transform = CATransform3DIdentity
		self.currentPlayerLayer.frame = CGRect(x: CGFloat(0), y: CGFloat(0), width: CGFloat(kScreenWidth), height: CGFloat(kScreenHeight))
	}
	
	
	private func releasePlayer() {
		if self.currentPlayerItem == nil {
			return
		}
		NotificationCenter.default.removeObserver(self)
		self.currentPlayerItem!.removeObserver(self, forKeyPath: "status")
		self.currentPlayerItem!.removeObserver(self, forKeyPath: "loadedTimeRanges")
		self.currentPlayerItem!.removeObserver(self, forKeyPath: "playbackBufferEmpty")
		self.currentPlayerItem!.removeObserver(self, forKeyPath: "playbackLikelyToKeepUp")
		if self.playbackTimeObserver != nil {
			self.player?.removeTimeObserver(self.playbackTimeObserver)
		}
		self.playbackTimeObserver = nil
		self.currentPlayerItem = nil
	}
	
	
	
	// MARK: - UI
	func buildVideoNavBar() {
		
		self.navBar!.backgroundColor = UIColor.rgb("000000", alpha: 0.5)
		self.navBar!.frame = CGRect(x: CGFloat(0), y: CGFloat(0), width: CGFloat(kScreenWidth), height: CGFloat(44))
		//当前时间
		if self.currentTimeLabel == nil {
			self.currentTimeLabel = UILabel()
			self.currentTimeLabel!.textColor = UIColor.rgb("ffffff", alpha: 1.0)
			self.currentTimeLabel!.font = UIFont.systemFont(ofSize: CGFloat(10.0))
			self.currentTimeLabel!.frame = CGRect(x: CGFloat(30), y: CGFloat(0), width: CGFloat(52), height: CGFloat(44))
			self.currentTimeLabel!.textAlignment = .right
			self.navBar!.addSubview(self.currentTimeLabel!)
		}
		//总时间
		if self.totalTimeLabel == nil {
			self.totalTimeLabel = UILabel()
			self.totalTimeLabel!.textColor = UIColor.rgb("ffffff", alpha: 1.0)
			self.totalTimeLabel!.font = UIFont.systemFont(ofSize: CGFloat(10.0))
			self.totalTimeLabel!.frame = CGRect(x: CGFloat(kScreenWidth - 52 - 15), y: CGFloat(0), width: CGFloat(52), height: CGFloat(44))
			self.totalTimeLabel!.textAlignment = .left
			self.navBar!.addSubview(self.totalTimeLabel!)
		}
		
		//进度条
		if self.videoProgressView == nil {
			self.videoProgressView = UIProgressView()
			self.videoProgressView!.progressTintColor = UIColor.rgb("ffffff", alpha: 1.0)
			//填充部分颜色
			self.videoProgressView!.trackTintColor = UIColor.rgb("ffffff", alpha: 0.18)
			// 未填充部分颜色
			self.videoProgressView!.frame = CGRect(x: CGFloat(62 + 30), y: CGFloat(21), width: CGFloat(kScreenWidth - 124 - 44), height: CGFloat(20))
			self.videoProgressView!.layer.cornerRadius = 1.5
			self.videoProgressView!.layer.masksToBounds = true
			let transform = CGAffineTransform(scaleX: 1.0, y: 1.5)
			self.videoProgressView!.transform = transform
			self.navBar!.addSubview(self.videoProgressView!)
		}
		//滑竿
		if self.playSlider == nil {
			self.playSlider = UISlider()
			self.playSlider!.frame = CGRect(x: CGFloat(62 + 30), y: CGFloat(0), width: CGFloat(kScreenWidth - 124 - 44), height: CGFloat(44))
			self.playSlider!.setThumbImage(UIImage(named: "icon_progress"), for: .normal)
			self.playSlider!.minimumTrackTintColor = UIColor.clear
			self.playSlider!.maximumTrackTintColor = UIColor.clear
			self.playSlider!.addTarget(self, action: #selector(self.playSliderChange), for: .valueChanged)
			//拖动滑竿更新时间
			self.playSlider!.addTarget(self, action: #selector(self.playSliderChangeEnd), for: .touchUpInside)
			//松手,滑块拖动停止
			self.playSlider!.addTarget(self, action: #selector(self.playSliderChangeEnd), for: .touchUpOutside)
			self.playSlider!.addTarget(self, action: #selector(self.playSliderChangeEnd), for: .touchCancel)
			self.navBar!.addSubview(self.playSlider!)
		}
		
		//暂停按钮
		if self.stopButton == nil {
			self.stopButton = UIButton(type: .custom)
			self.stopButton!.frame = CGRect(x: CGFloat(0), y: CGFloat(0), width: CGFloat(44), height: CGFloat(44))
			self.stopButton!.addTarget(self, action: #selector(self.resumeOrPause), for: .touchUpInside)
			self.stopButton!.setImage(UIImage(named: "icon_pause"), for: .normal)
			self.stopButton!.setImage(UIImage(named: "icon_pause_hl"), for: .highlighted)
			self.navBar!.addSubview(self.stopButton!)
		}
		//全屏按钮
		if self.screenButton == nil {
			self.screenButton = UIButton()
			self.screenButton!.frame = CGRect(x: CGFloat(kScreenWidth - 40), y: CGFloat(0), width: CGFloat(44), height: CGFloat(44))
			self.screenButton!.addTarget(self, action: #selector(self.fullScreen), for: .touchUpInside)
			self.screenButton!.setImage(UIImage(named: "quanping"), for: .normal)
			self.screenButton!.setImage(UIImage(named: "quanping"), for: .highlighted)
			self.navBar!.addSubview(self.screenButton!)
		}

	}
	
	
	/// 手指结束拖动，播放器从当前点开始播放，开启滑竿的时间走动
	func playSliderChangeEnd(_ slider: UISlider) {
		self.seek(CGFloat(slider.value))
		self.updateCurrentTime(CGFloat(slider.value))
		self.stopButton!.setImage(UIImage(named: "icon_pause"), for: .normal)
		self.stopButton!.setImage(UIImage(named: "icon_pause_hl"), for: .highlighted)
	}
	
	/// 手指正在拖动，播放器继续播放，但是停止滑竿的时间走动
	func playSliderChange(_ slider: UISlider) {
		self.updateCurrentTime(CGFloat(slider.value))
	}
	
	
	
	func resumeOrPause() {
		if self.currentPlayerItem == nil {
			return
		}
		if self.state == JDPlayerState.playing {
			self.stopButton!.setImage(UIImage(named: "icon_play"), for: .normal)
			self.stopButton!.setImage(UIImage(named: "icon_play_hl"), for: .highlighted)
			self.player?.pause()
			self.state = JDPlayerState.pause
		}
		else if self.state == JDPlayerState.pause {
			self.stopButton!.setImage(UIImage(named: "icon_pause"), for: .normal)
			self.stopButton!.setImage(UIImage(named: "icon_pause_hl"), for: .highlighted)
			self.player?.play()
			self.state = JDPlayerState.playing
		}
		
		self.isPauseByUser = true
	}
	
	// MARK: - 控件拖动
	
	func setPlaySliderValue(_ time: CGFloat) {
		self.playSlider!.minimumValue = 0.0
		self.playSlider!.maximumValue = Float(time)
	}
	
	func updateCurrentTime(_ time: CGFloat) {
		let videocurrent = ceil(Double(time))
		var str: String? = nil
		if videocurrent < 3600 {
			str = String(format: "%02li:%02li", lround(floor(videocurrent / 60.0)), lround(floor(videocurrent / 1.0)) % 60)
		}
		else {
			str = String(format: "%02li:%02li:%02li", lround(floor(videocurrent / 3600.0)), lround(floor(Double(Int(videocurrent) % 3600)) / 60.0), lround(floor(videocurrent / 1.0)) % 60)
		}
		self.currentTimeLabel!.text = str
	}
	
	func updateTotolTime(_ time: CGFloat) {
		let videoLenth = ceil(Double(time))
		var strtotol: String? = nil
		if videoLenth < 3600 {
			strtotol = String(format: "%02li:%02li", lround(floor(videoLenth / 60.0)), lround(floor(videoLenth / 1.0)) % 60)
		}
		else {
			strtotol = String(format: "%02li:%02li:%02li", lround(floor(videoLenth / 3600.0)), lround(floor(Double(Int(videoLenth) % 3600)) / 60.0), lround(floor(videoLenth / 1.0)) % 60)
		}
		self.totalTimeLabel!.text = strtotol
	}
	
	func updateVideoSlider(_ currentSecond: CGFloat) {
		self.playSlider!.setValue(Float(currentSecond), animated: true)
	}
	
	
	
	// MARK: - observer
	
	func appDidEnterBackground() {
		if self.stopWhenAppDidEnterBackground {
			self.pause()
			self.state = JDPlayerState.pause
			self.isPauseByUser = false
		}
	}
	
	func appDidEnterPlayGround() {
		if !self.isPauseByUser {
			self.resume()
			self.state = JDPlayerState.playing
		}
	}
	
	func playerItemDidPlayToEnd(_ notification: Notification) {
		self.stop()
	}
	
	//在监听播放器状态中处理比较准确
	func playerItemPlaybackStalled(_ notification: Notification) {
		// 这里网络不好的时候，就会进入，不做处理，会在playbackBufferEmpty里面缓存之后重新播放
		print("buffing-----buffing")
	}
	
	override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
		let playerItem = (object as? AVPlayerItem)
		if playerItem == nil {
			DebugLog("【失败】playerItem == nil")
			return
		}
		if (keyPath == "status") {
			DebugLog(playerItem!.status.rawValue)
			if playerItem!.status == .readyToPlay {
				self.monitoringPlayback(playerItem!)
				// 给播放器添加计时器
			}
			else if playerItem!.status == .failed || playerItem!.status == .unknown {
				self.stop()
			}
		}
		else if (keyPath == "loadedTimeRanges") {
			//监听播放器的下载进度
			self.calculateDownloadProgress(playerItem!)
		}
		else if (keyPath == "playbackBufferEmpty") {
			//监听播放器在缓冲数据的状态
//			XCHudHelper.sharedInstance().showHud(on: self.showView, caption: nil, image: nil, acitivity: true, autoHideTime: 0)
			
			
			if playerItem!.isPlaybackBufferEmpty {
				self.state = JDPlayerState.buffering
				self.bufferingSomeSecond()
			}
		}
	}
	
	func monitoringPlayback(_ playerItem: AVPlayerItem) {
		
		self.duration = CGFloat(playerItem.duration.seconds)
		//视频总时间
		self.player!.play()
		self.updateTotolTime(self.duration)
		self.setPlaySliderValue(self.duration)
		
		self.playbackTimeObserver = self.player?.addPeriodicTimeObserver(forInterval: CMTime(value: 1, timescale: 1), queue: nil, using: { [unowned self] (time) in
			
//			var current: CGFloat = playerItem.currentTime().value / playerItem.currentTime().timescale
			
			let current: CGFloat = CGFloat(playerItem.currentTime().seconds)
			
			self.updateCurrentTime(current)
			self.updateVideoSlider(current)
			if self.isPauseByUser == false {
				self.state = JDPlayerState.playing
			}
			// 不相等的时候才更新，并发通知，否则seek时会继续跳动
			if self.current != current {
				self.current = current
				if self.current > self.duration {
					self.duration = self.current
				}
				NotificationCenter.default.post(name: NSNotification.Name(rawValue: kJDPlayerProgressChangedNotification), object: nil)
			}
		}) as! NSObject!
	}
	
	func calculateDownloadProgress(_ playerItem: AVPlayerItem) {
		let loadedTimeRanges = playerItem.loadedTimeRanges
		let timeRange = loadedTimeRanges.first!.timeRangeValue
		
		// 获取缓冲区域
		let startSeconds = CMTimeGetSeconds(timeRange.start)
		let durationSeconds = CMTimeGetSeconds(timeRange.duration)
		let timeInterval = startSeconds + durationSeconds
		// 计算缓冲总进度
		let duration: CMTime = playerItem.duration
		let totalDuration = Float64(CMTimeGetSeconds(duration))
		
		self.loadedProgress = CFloat(timeInterval / totalDuration)
		self.videoProgressView!.setProgress(self.loadedProgress, animated: true)
	}
	
	func bufferingSomeSecond() {
		// playbackBufferEmpty会反复进入，因此在bufferingOneSecond延时播放执行完之前再调用bufferingSomeSecond都忽略
		var isBuffering: Bool = false
		if isBuffering {
			return
		}
		isBuffering = true
		// 需要先暂停一小会之后再播放，否则网络状况不好的时候时间在走，声音播放不出来
		self.player?.pause()
		DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + Double(Int64(2 * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC), execute: {() -> Void in
			// 如果此时用户已经暂停了，则不再需要开启播放了
			if self.isPauseByUser {
				isBuffering = false
				return
			}
			self.player?.play()
			// 如果执行了play还是没有播放则说明还没有缓存好，则再次缓存一段时间
			isBuffering = false
			if !self.currentPlayerItem!.isPlaybackLikelyToKeepUp {
				self.bufferingSomeSecond()
			}
		})
	}
	
	
	
	// MARK: - JDResourceLoaderDelegate
	
	
	
	//网络中断：-1005
	//无网络连接：-1009
	//请求超时：-1001
	//服务器内部错误：-1004
	//找不到服务器：-1003
	func didFailLoading(_ loader: JDResourceLoader, _ task: JDVideoRequestTask, _ errorCode: Int) {
		var str: String? = nil
		switch errorCode {
		case -1001:
			str = "请求超时"
		case -1003, -1004:
			str = "服务器错误"
		case -1005:
			str = "网络中断"
		case -1009:
			str = "无网络连接"
		default:
			str = "\("(_errorCode)")"
		}
		
		// HUD 提醒
		JDToast.show(str!)
	}
	
	func didFinishLoading(_ loader: JDResourceLoader, _ task: JDVideoRequestTask) {
		self.isFinishLoad = task.isFinishLoad
		
		let path = NSSearchPathForDirectoriesInDomains(.cachesDirectory, .userDomainMask, true).last! + "/下载完成.mp3"
		task.saveFile(path)
	}
	
}
